package site.xuqing.socketbus;

import android.app.Activity;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.net.ServerSocket;

import androidx.fragment.app.Fragment;
import site.xuqing.nobean.obj.INonObject;
import site.xuqing.nobean.obj.NonObject;
import site.xuqing.socketbus.core.SocketClient;
import site.xuqing.socketbus.core.SocketServer;
import site.xuqing.socketbus.listener.OnMsgReceive;
import site.xuqing.socketbus.listener.OnSocketServerClientListener;
import site.xuqing.socketbus.uitls.NoBeanUtil.Route;
import site.xuqing.socketbus.uitls.PortUtil;
import site.xuqing.socketbus.uitls.RouteUtil;

/**
 * @author xuqing
 * @Description SocketBus启动Api类
 * @createTime 2022年01月21日 09:59:24
 */
public class SocketBus {
    private int port=-1;
    private SocketServer mSocketServer;
    
    private static class SocketBusHolder {
        private static final SocketBus INSTANCE = new SocketBus();
    }
    
    private SocketBus() {}
    
    public static SocketBus getInstance() {
        return SocketBusHolder.INSTANCE;
    }
    
    /**
     * 该方法为初始化方法，需要在请求到存储权限后调用调用
     */
    public void initSocketServer(){
        if (PortUtil.getPort() != -1) {
            port = PortUtil.getPort();
            new TestServer(port).start();
        } else {
            port = PortUtil.DEFAULT_PORT;
            realInitSocketServer();
        }
    }
    
    public void realInitSocketServer(){
        if (port==-1){
            throw new RuntimeException("please use initSocketServer() instead of realInitSocketServer() method!");
        }
        mSocketServer = new SocketServer(port, new OnSocketServerClientListener() {
            @Override
            public void onSuccess() {
                //把port存储到本地，以供跨进程使用
                PortUtil.setPort(port);
            }
        
            @Override
            public void onError() {
                //换一个port，重启SocketServer
                mSocketServer.setServerPort(port++);
                mSocketServer.start();
            }
        });
        mSocketServer.start();
    }
    
    /**
     * 该方法为连接服务器方法，在需要使用的地方调用
     */
    public SocketClient clientSocketServer(Activity activity, OnMsgReceive onMsgReceive) {
        return clientSocketServer((Object) activity, onMsgReceive);
    }
    
    public SocketClient clientSocketServer(Fragment fragment, OnMsgReceive onMsgReceive) {
        return clientSocketServer((Object) fragment, onMsgReceive);
    }
    
    public SocketClient clientSocketServer(Object object, OnMsgReceive onMsgReceive) {
        return clientSocketServer(RouteUtil.getRoute(object), onMsgReceive);
    }
    
    /**
     * 直接绑定一个route，在发起的地方使用该route便可以接收到消息
     *
     * @param route route
     * @return SocketClient
     */
    public SocketClient clientSocketServer(String route, OnMsgReceive onMsgReceive) {
        if (PortUtil.getPort() != -1) {
            port = PortUtil.getPort();
        } else {
            throw new RuntimeException("please call initSocketServer() before call this method!");
        }
        SocketClient mSocketClient = new SocketClient(port, route, onMsgReceive);
        mSocketClient.start();
        return mSocketClient;
    }
    
    /**
     * 清除内存
     *
     * @param client   SocketClient
     * @param activity Activity
     */
    public void finish(SocketClient client, Activity activity) {
        finish(client, (Object) activity);
    }
    
    public void finish(SocketClient client, Fragment fragment) {
        finish(client, (Object) fragment);
    }
    
    public void finish(SocketClient client, Object object) {
        finish(client, object.getClass().getCanonicalName());
    }
    
    public void finish(SocketClient client, String route) {
        client.getClientSendHandler().sendQuit(new NonObject().setValue("route", route));
        client.close();
    }
    
    public void sendMessage(SocketClient socketClient, Route route, INonObject data) {
        if (socketClient == null) {
            throw new RuntimeException("SocketClient is null,please check your code!");
        }
        socketClient.getClientSendHandler().sendMsg(route, data);
    }
    
    private static class TestServer extends Thread{
        private final int port;
        public TestServer(int port) {
            this.port=port;
        }
    
        @Override
        public void run() {
            //测试 port,如果启动相同port的server必定会报错
            try {
                ServerSocket server = new ServerSocket();
                server.bind(new InetSocketAddress(Inet4Address.getLocalHost(), port), 50);
                server.close();
                SocketBus.getInstance().realInitSocketServer();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}
